package network

import (
	"gomir/mlog"
	"reflect"
)

func DecodeProtocol(id int, data []byte) (p Protocol) {
	meta := ProtoMetaByID(id)
	if meta == nil {
		return nil
	}
	p = meta.NewProto()
	if p == nil {
		return nil
	}
	r := &BytesReader{&data}

	defer func() {
		if err := recover(); err != nil {
			mlog.Panic(err)
			p = nil
		}
	}()

	decode(p, r)
	return
}

func decode(v interface{}, r *BytesReader) {
	rv := reflect.ValueOf(v)
	if rv.Type().Kind() == reflect.Ptr {
		rv = rv.Elem()
	}
	decodeValue(rv, r)
}

func decodeValue(rv reflect.Value, r *BytesReader) {
	if rv.Kind() == reflect.Ptr {
		//rv = rv.Elem()
		panic("decodeValue can't be ptr") //客户端协议中没有指针
	}
	switch rv.Kind() {
	case reflect.Bool:
		rv.SetBool(r.ReadBool())
	case reflect.Int8:
		rv.SetInt(int64(r.ReadInt8()))
	case reflect.Uint8:
		rv.SetUint(uint64(r.ReadUint8()))
	case reflect.Int16:
		rv.SetInt(int64(r.ReadInt16()))
	case reflect.Uint16:
		rv.SetUint(uint64(r.ReadUint16()))
	case reflect.Int32, reflect.Int:
		rv.SetInt(int64(r.ReadInt32()))
	case reflect.Uint32, reflect.Uint:
		rv.SetUint(uint64(r.ReadUint32()))
	case reflect.Int64:
		rv.SetInt(r.ReadInt64())
	case reflect.Uint64:
		rv.SetUint(r.ReadUint64())
	case reflect.Float32:
		rv.SetFloat(float64(r.ReadFloat32()))
	case reflect.Float64:
		rv.SetFloat(r.ReadFloat64())
	case reflect.String:
		rv.SetString(r.ReadString())
	case reflect.Array:
		for i := 0; i < rv.Len(); i++ {
			decodeValue(rv.Index(i), r)
		}
	case reflect.Slice:
		l := int(r.ReadInt32())
		switch rv.Type().Elem().Kind() {
		case reflect.Int8, reflect.Uint8:
			rv.SetBytes(r.ReadBytes(l))
		default:
			v := reflect.MakeSlice(rv.Type(), l, l)
			rv.Set(v)
			for i := 0; i < l; i++ {
				decodeValue(v.Index(i), r)
			}
		}
	case reflect.Struct:
		for i := 0; i < rv.NumField(); i++ {
			decodeValue(rv.Field(i), r)
		}
	default:
		panic("decodeValue unkown type")
	}
}
